//
//  JKDeviceInfo.m
//  DeviceJudge
//
//  Created by 王冲 on 2018/11/7.
//  Copyright © 2018年 JK科技有限公司. All rights reserved.
//
/**
   在开发中，我们经常需要获取设备的型号（如 iPhone X，iPhone 8 Plus 等）以进行数据统计，或者做不同的适配。但苹果并没有提供相应的系统 API 让我们直接取得当前设备的型号。
   其中，UIDevice 有一个属性 model 只是用于获取 iOS 设备的类型，如 iPhone，iPod touch，iPad 等；而其另一个属性 name 表示当前设备的名称，由用户在设置》通用》关于》名称中设定，如 My iPhone，xxx 的 iPhone 等。然而，我们无法根据这两个值获得具
   不过，每一种 iOS 设备型号都有对应的一个或多个硬件编码/标识符，称为 device model 或者叫 machine name体的型号。
   所以，通常的做法是，先获取设备的 device model 值，再手动映射为具体的设备型号（或者直接把device model 值传给后端，让后端去做映射，这样的好处是可以随时兼容新设备）。
 
   例如：去年发布的第一代 iPhone X 对应的 device mode 为 iPhone10,3 和 iPhone10,6，而今年最新发布 iPhone XS 对应 iPhone11,2，iPhone XS Max 对应 iPhone11,4 和 iPhone11,6，iPhone XR 对应 iPhone11,8，完整的 device mode 数据参考 Wiki：https://www.theiphonewiki.com/wiki/Models
   综上，我们可以先获取 device model 值，记为 platform，然后进行对比判断，转换成具体的设备型号，实现代码如下所示。
   下面只给了对 iPhone 设备型号的判断，而完整的包括 iPad 和 iPod touch 型号
 */
// https://www.theiphonewiki.com/wiki/Models

#import "JKDeviceInfo.h"

#import "sys/utsname.h"
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>

@implementation JKDeviceInfo

#pragma mark 一、获取系统相关信息

#pragma mark 1.1、返回当前设备模型名字
+(NSString *)deviceName{
    
    static NSString *device_name = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        device_name = [self platformString];
     
        
        // NSLog(@"deviceName = %@",device_name);
        
        if (device_name.length == 0) {
            
            device_name = @"iphone";
        }
        
    });
    
    return device_name;
}

+(NSString *)platformString{
    
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    
    if ([deviceString isEqualToString:@"iPhone11,6"]) return @"iPhone XS Max";
    if ([deviceString isEqualToString:@"iPhone11,4"]) return @"iPhone XS Max";
    if ([deviceString isEqualToString:@"iPhone11,2"]) return @"iPhone XS";
    if ([deviceString isEqualToString:@"iPhone11,8"]) return @"iPhone XR";
    if ([deviceString isEqualToString:@"iPhone10,6"]) return @"iPhone X";
    if ([deviceString isEqualToString:@"iPhone10,3"]) return @"iPhone X";
    if ([deviceString isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";
    if ([deviceString isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";
    if ([deviceString isEqualToString:@"iPhone10,4"]) return @"iPhone 8";
    if ([deviceString isEqualToString:@"iPhone10,1"]) return @"iPhone 8";
    if ([deviceString isEqualToString:@"iPhone9,4"]) return @"iPhone 7 Plus";
    if ([deviceString isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";
    if ([deviceString isEqualToString:@"iPhone9,3"]) return @"iPhone 7";
    if ([deviceString isEqualToString:@"iPhone9,1"]) return @"iPhone 7";
    if ([deviceString isEqualToString:@"iPhone8,4"]) return @"iPhone SE";
    if ([deviceString isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";
    if ([deviceString isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";
    if ([deviceString isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";
    if ([deviceString isEqualToString:@"iPhone7,2"]) return @"iPhone 6";
    if ([deviceString isEqualToString:@"iPhone6,2"]) return @"iPhone 5s";
    if ([deviceString isEqualToString:@"iPhone6,1"]) return @"iPhone 5s";
    if ([deviceString isEqualToString:@"iPhone5,4"]) return @"iPhone 5c";
    if ([deviceString isEqualToString:@"iPhone5,3"]) return @"iPhone 5c";
    if ([deviceString isEqualToString:@"iPhone5,2"]) return @"iPhone 5";
    if ([deviceString isEqualToString:@"iPhone5,1"]) return @"iPhone 5";
    if ([deviceString isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";
    if ([deviceString isEqualToString:@"iPhone3,3"]) return @"iPhone 4";
    if ([deviceString isEqualToString:@"iPhone3,2"]) return @"iPhone 4";
    if ([deviceString isEqualToString:@"iPhone3,1"]) return @"iPhone 4";
    if ([deviceString isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS";
    if ([deviceString isEqualToString:@"iPhone1,2"]) return @"iPhone 3G";
    if ([deviceString isEqualToString:@"iPhone1,1"]) return @"iPhone";
    if ([deviceString isEqualToString:@"iPad5,2"]) return @"iPad mini 4";
    if ([deviceString isEqualToString:@"iPad5,1"]) return @"iPad mini 4";
    if ([deviceString isEqualToString:@"iPad4,9"]) return @"iPad mini 3";
    if ([deviceString isEqualToString:@"iPad4,8"]) return @"iPad mini 3";
    if ([deviceString isEqualToString:@"iPad4,7"]) return @"iPad mini 3";
    if ([deviceString isEqualToString:@"iPad4,6"]) return @"iPad mini 2";
    if ([deviceString isEqualToString:@"iPad4,5"]) return @"iPad mini 2";
    if ([deviceString isEqualToString:@"iPad4,4"]) return @"iPad mini 2";
    if ([deviceString isEqualToString:@"iPad2,7"]) return @"iPad mini";
    if ([deviceString isEqualToString:@"iPad2,6"]) return @"iPad mini";
    if ([deviceString isEqualToString:@"iPad2,5"]) return @"iPad mini";
    
    return deviceString;
}


#pragma mark 1.2、获取设备名称
+ (NSString *)getDeviceName
{
    NSString *strName = [[UIDevice currentDevice] name];
    
    // NSLog(@"%@",strName);
    return strName;
}

#pragma mark 1.3、获取手机名称
+ (NSString *)getIphoneName
{
    NSString *phoneName = [[UIDevice currentDevice] model];
    
    return phoneName;
}

#pragma mark 1.4、获取手机系统版本
+ (NSString *)getIphone_version
{
    NSString *strSysVersion = [[UIDevice currentDevice] systemVersion];
    
    //NSLog(@"%@",strSysVersion);
    
    return strSysVersion;
}

#pragma mark 1.5、获取APP的版本号
+ (NSString *)getApp_bundelID{
    
    NSString *bundelID = [NSBundle mainBundle].infoDictionary[@"CFBundleVersion"];
    return bundelID;
}

#pragma mark 1.6、系统名称
+ (NSString *)getIOSName
{
    NSString *strSysName = [[UIDevice currentDevice] systemName];
    return strSysName;
}

#pragma mark 二、获取硬件相关信息

#pragma mark 2.1、获取CPU类型
+ (NSString *)getHardParam  // 返回CPU类型
{
    NSMutableString *cpu = [[NSMutableString alloc] init];
    size_t size;
    cpu_type_t type;
    cpu_subtype_t subtype;
    size = sizeof(type);
    sysctlbyname("hw.cputype", &type, &size, NULL, 0);
    
    size = sizeof(subtype);
    sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
    
    // values for cputype and cpusubtype defined in mach/machine.h
    if (type == CPU_TYPE_X86)
    {
        [cpu appendString:@"x86 "];
        // check for subtype ...
        
    } else if (type == CPU_TYPE_ARM)
    {
        [cpu appendString:@"ARM"];
        [cpu appendFormat:@",Type:%d",subtype];
    }
    return cpu;
}

#pragma mark 2.2、获取运营商信息
+ (NSString *)getTelephonyInfo    
{
    CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
    CTCarrier *carrier = [info subscriberCellularProvider];
    NSString *mCarrier = [NSString stringWithFormat:@"%@",[carrier carrierName]];
    
    return mCarrier;
}

#pragma mark 2.3、获取设备总内存
+ (NSUInteger)getTotalMemoryBytes
{
    size_t size = sizeof(int);
    int results;
    int mib[2] = {CTL_HW, HW_PHYSMEM};
    sysctl(mib, 2, &results, &size, NULL, 0);
    return (NSUInteger) results/1024/1024;
}

#pragma mark 2.4、异常信息收集处理
// 异常收集处理
void UncaughtExceptionHandler(NSException *exception) {
    NSArray *arr = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    
    // NSLog(@"%@,%@,%@",arr,reason,name);
}

// 写入异常信息
-(void)writeACrashMessage
{
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}

#pragma mark 2.5、获取设备中运行的内存
+ (NSArray *)getRunningProcesses {
    
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t miblen = 4;
    
    size_t size;
    int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
    
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
    
    do {
        
        size += size / 10;
        newprocess = realloc(process, size);
        
        if (!newprocess){
            
            if (process){
                free(process);
            }
            
            return nil;
        }
        
        process = newprocess;
        st = sysctl(mib, miblen, process, &size, NULL, 0);
        
    } while (st == -1 && errno == ENOMEM);
    
    if (st == 0){
        
        if (size % sizeof(struct kinfo_proc) == 0){
            int nprocess = size / sizeof(struct kinfo_proc);
            
            if (nprocess){
                
                NSMutableArray * array = [[NSMutableArray alloc] init];
                
                for (int i = nprocess - 1; i >= 0; i--){
                    
                    NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
                    NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];
                    
                    NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName, nil]
                                                                        forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName", nil]];
                    [array addObject:dict];
                }
                
                free(process);
                return array;
            }
        }
    }
    
    
    return nil;
}

#pragma mark 2.6、获取网络类型
+(NSString*)getNetworkType
{
    /**
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyGPRS          __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyEdge          __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyWCDMA         __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyHSDPA         __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyHSUPA         __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyCDMA1x        __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyCDMAEVDORev0  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyCDMAEVDORevA  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyCDMAEVDORevB  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyeHRPD         __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     CORETELEPHONY_EXTERN NSString * const CTRadioAccessTechnologyLTE           __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_7_0);
     **/
    CTTelephonyNetworkInfo* info=[[CTTelephonyNetworkInfo alloc]init];
    return info.currentRadioAccessTechnology;
}

#pragma mark 三、电池相关的信息
#pragma mark 判断当前设备电池状态
+(NSString *)batteryStatues{
    
    /**
     UIDeviceBatteryStateUnknown,
     UIDeviceBatteryStateUnplugged,   // 未充电，使用电池
     UIDeviceBatteryStateCharging,    // 充电中，并且电量小于 100%
     UIDeviceBatteryStateFull,        // 充电中, 电量已达 100%
     */
    
    [UIDevice currentDevice].batteryMonitoringEnabled = YES; //开启电量监控，默认不开启
    if ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) return @"正在充电中，且电量不足100";
    if ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateUnplugged) return @"未充电，使用电池";
    if ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull) return @"充电中, 电量已达 100%";
    
    //当前电量，小数[0,1] ,如果[[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateUnknown时，则为1.0
    //NSLog(@"当前电量%f",[[UIDevice currentDevice] batteryLevel]);
    
    return [NSString stringWithFormat:@"当前电量%f",[[UIDevice currentDevice] batteryLevel]];
}

@end
